﻿
#include "CoreHeadForClient.h"
#include "MemBlockPool2.h"

CMemBlockPool2::CMemBlockPool2(int iMsgBlockSize, int nInitElementCount, int nMaxElementCount)
{
	m_iMsgBlockSize = iMsgBlockSize;	// 消息元素的长度

	m_nInitElementCount = nInitElementCount;	// 池的初始元素数量
	m_nMaxElementCount = nMaxElementCount;		// 池内元素的上限值

	m_nAfterExpandOrShrinkCount = 0;

	if(m_nInitElementCount.load()>=64)
		m_nExpandStep = m_nInitElementCount.load()/5;
	else
		m_nExpandStep = m_nInitElementCount.load();

	m_lPeriod = 1000;	// 定时器每秒响应一次，但不一定收缩池，以 ms 为单位

	m_fExpandParam = 1.25;	// 扩展系数，收缩时只收至初始值乘以扩充系数之处

	m_iExpandFailTimes = 10;	// 扩展失败次数
	m_iExpandFailSleepTime = 1000;	// 扩展失败时的睡眠时间，以 ms 为单位

	m_lRetrieveCount = 0;	// 出池的数量
	m_lRecycleCount = 0;	// 归池的数量

	m_bShrinkPool = true;	// 是否允许收缩
	m_iDieSpace = 4000;		// 未归池的时差判定的时长
}

CMemBlockPool2::~CMemBlockPool2(void)
{
	uninit();
}

int CMemBlockPool2::Test(int** pp)
{
	return 0;
}

// 获得是否允许收缩
bool CMemBlockPool2::get_shrink_pool()	
{
	return m_bShrinkPool;
}

// 设置是否允许收缩
void CMemBlockPool2::set_shrink_pool(bool bShrinkPool)	
{
	m_bShrinkPool = bShrinkPool;
}

// 设置池内初始元素的数量
void CMemBlockPool2::set_init_block_count(int nInitBlkCount)
{
	m_nInitElementCount = nInitBlkCount;
}

// 设置池内元素的上限值
void CMemBlockPool2::set_max_block_count(int nMaxBlkCount)
{
	m_nMaxElementCount = nMaxBlkCount;
}

// 设置扩展失败次数
void CMemBlockPool2::set_expand_fail_times(int iExpandFailTimes)
{
	m_iExpandFailTimes = iExpandFailTimes;		
}

// 设置扩展失败时的睡眠时间，以 ms 为单位
void CMemBlockPool2::set_expand_fail_sleep_time(int iExpandFailSleepTime)
{
	m_iExpandFailSleepTime = iExpandFailSleepTime;	
}

// 获得池里内存块的尺寸
int CMemBlockPool2::get_mem_block_size()
{
	return m_iMsgBlockSize;
}

// 获得池内初始元素数量
int CMemBlockPool2::get_init_element_count()
{
	return m_nInitElementCount.load();
}

// 初始化
bool CMemBlockPool2::init()
{
	bool bResult = false;

	if (expand_pool("CMemBlockPool2::init", m_nInitElementCount.load(), false) > 0)	// 扩展池的尺寸
	{
		bResult = true;
	}

	return bResult;
}

// 结束初始化，与 init() 成对出现
bool CMemBlockPool2::uninit()
{
	std::lock_guard<std::recursive_mutex> guard(m_lock);

	int iRes = 0;
	int	iCount = (int)m_stack.size();
	std::deque<CMemBlock2*>::iterator it;
	CMemBlock2* pMsgBlock = NULL;
	while((it=m_stack.begin()) != m_stack.end())
	{
		pMsgBlock = (CMemBlock2*)(*it);
		if(pMsgBlock)
		{
			m_stack.erase(it);
			delete pMsgBlock;
		}
		else
		{
			log("消息池内有元素是空值，%s  \n", "CMemBlockPool2::uninit");
			iRes = 10;
		}
	}

	if(iCount>0)
	{
			log("消息池释放完毕 \n");
	}

	return (0==iRes);
}

// 出池
bool CMemBlockPool2::retrieve(CMemBlock2** ppMsgBlock, char* pszTextMark, bool bIsWait)
{
	std::lock_guard<std::recursive_mutex> guard(m_lock);

	using namespace std::chrono;

	*ppMsgBlock = NULL;

	bool	bResult = false;
	int		iLoopCount = 0;
	bool	bExpand = false;

	CMemBlock2*	pMsgBlk = NULL;

	do
	{
		if( (m_nAfterExpandOrShrinkCount - (int)(m_stack.size())) < m_nMaxElementCount.load() )
		{
			if(m_stack.size() > 0)
			{
				pMsgBlk = m_stack.front();
				m_stack.pop_front();  // 从池中将该记录移除，但该记录要传出并使用，所以不能 delete

				#if 0
					pMsgBlk->reset();	// 速度快，说明 memset 是很耗时的
				#else
					pMsgBlk->clear();	// 虽然慢，但出池的数据很干净，方便应用层出问题时追踪出池的数据
				#endif

				pMsgBlk->m_bInPool = false;	// 在池外

				if(pszTextMark)
				{
					int iLen = CMemBlock2::min2(CMemBlock2::TEXT_MARK_LEN - 1, strlen(pszTextMark));

					// 设置文字标识，目的是在查询未释放的内存是知道是程序的哪一句申请的
					pMsgBlk->set_text_mark(pszTextMark, iLen);

					//pMsgBlk->timeOutPool = ::GetTickCount64();	// 出池时间
					// 出池时间，获得当前时间，也可以这样定义  auto 类型
					pMsgBlk->timeOutPool = std::chrono::high_resolution_clock::now();
				}

				*ppMsgBlock = pMsgBlk;

				//InterlockedIncrement64 (&m_lRetrieveCount);
				++m_lRetrieveCount;

				bResult = true;
			}
			else
			{
				bExpand = ( expand_pool(pszTextMark, m_nExpandStep, true) >0 )? true:false;
				
			}
		}

		iLoopCount++;

		char szError[256] = {0};

		if((pMsgBlk == NULL) && bIsWait && !bExpand)  
		{
			#if 1
				// 这种睡眠的方式并不能解决问题，坏处是会导致所有的 put 都卡住，好处是几乎不会丢包
				// 实在卡得厉害就加大 nMaxBlkCount 值
				if( iLoopCount < m_iExpandFailTimes )	// 扩展失败次数
				{
					sprintf(szError, "%s CMemBlockPool2 睡后继续扩展，扩展失败次数 %d\n", pszTextMark, iLoopCount);

					std::this_thread::sleep_for(std::chrono::milliseconds(m_iExpandFailSleepTime));		// 扩展失败时的睡眠时间，以 ms 为单位
				}
				else
				{
					bResult = false;

					sprintf(szError, "CMemBlockPool2 池中元素已到达 %d 上限，\n    无法再扩展,出池的数量 %d 归池的数量 %d \n",
						m_nMaxElementCount.load(),
						m_lRetrieveCount.load(),
						m_lRecycleCount.load());

					log("%s", szError);

					break;
				}
			#else
				// 将扩展失败的结果交给应用层，由应用层睡眠解决，但应用层处理会丢包
				sprintf(szError, "CMemBlockPool2 池中元素已到达 %d 上限，\n    无法再扩展,出池的数量 %d 归池的数量 %d \n",
							m_nMaxElementCount.load(),
							m_lRetrieveCount.load(),
							m_lRecycleCount.load() );

				log(szError);

				bResult = false;
				break;
			#endif
		}

	}while((pMsgBlk == NULL) && (bIsWait || bExpand));  // 出池失败或扩展池失败，继续循环

	return bResult;
}

/* --------------------------------------------------------------------------
函数说明：归池
传入参数：
	pMsgBlock	一条消息记录
	szFunName	调用 recycle 的函数名
返回值：
	成功则返回 true，否则返回 false 。
--------------------------------------------------------------------------*/
bool CMemBlockPool2::recycle(CMemBlock2* pMsgBlock, const char* szFunName)
{
	std::lock_guard<std::recursive_mutex> guard(m_lock);

	bool	bResult = false;

	if(pMsgBlock)
	{
		if(pMsgBlock->m_bInPool)	// 已经在池内啦，不允许重复归池
		{

			int64_t lChannelNo;
			int iMainCode = 0;
			int iSubCode = 0;
			char* pData = NULL;
			int iDataLen = 0;
			int iRes = 0;

			// 获得内核消息的真实数据
			iRes =  get_core_msg_data(pMsgBlock, &lChannelNo, &iMainCode, &iSubCode, pData, &iDataLen);

			char szTmp[128] = {0};
			if(szFunName)
				sprintf(szTmp, "%s 函数 pMsgBlock 试图重复归池 %d,MainCode %d,SubCode %d", szFunName, pMsgBlock, iMainCode, iSubCode);
			else
				sprintf(szTmp, "pMsgBlock 试图重复归池 %d,MainCode %d,SubCode %d", pMsgBlock, iMainCode, iSubCode);

			log("%s", szTmp);

			return false;
		}
		else
		{
			pMsgBlock->m_bInPool = true;	// 设置为在池内

			//pMsgBlock->timeOutPool = 0;	// 出池时间
			pMsgBlock->bTimeOutPool = false;			// 有出池时间，若为零值表示在池内

			pMsgBlock->clear_text_mark();	// 清空文字标识

			m_stack.push_back(pMsgBlock);
		
			//InterlockedIncrement64 (&m_lRecycleCount);
			++m_lRecycleCount;
		
			bResult = true;
		}
	}
	else
	{
		bResult = false;
	}

	return bResult;
}

/* --------------------------------------------------------------------------
函数说明：扩展池的尺寸
传入参数：
	nCount			需要扩展的尺寸
	bLimitExpandLen	控制扩展的长度
	bLock			扩展的过程中加锁，
返回值：
	实际扩展的尺寸
--------------------------------------------------------------------------*/
int CMemBlockPool2::expand_pool(char* pszTextMark, int nCount, bool bLimitExpandLen)
{
	if( nCount <= 0 )
		return 0;

	// 主要是因为  Retrieve 调用 expand_pool 时 CThreadGuardWrite 镶套了而导致死锁
	//std::lock_guard<std::recursive_mutex> guard(m_lock);
	std::lock_guard<std::recursive_mutex> guard(m_lock);		// 可以递归，不怕镶套

	int nExpandCount = 0;

	if(bLimitExpandLen)
	{
		nExpandCount = ( nCount > m_nExpandStep )? m_nExpandStep : nCount;
	}
	else
	{
		nExpandCount = nCount;
	}

	int iFactCount = 0;	// 实际扩展的数量

	for(int i = 0; i < nExpandCount; i++)
	{
		CMemBlock2* pNew = NULL;
		pNew = new CMemBlock2(pszTextMark, m_iMsgBlockSize);
		
		if(pNew)
		{
			try
			{
				pNew->m_bInPool = true;	// 在池内

				std::pair< MAP_ORIGINAL_STUB::iterator, bool > pr;
				pr = m_mapOriginalStub.insert(PAIR_ORIGINAL_STUB(pNew,0));	// 加入原始的存根

				if(true == pr.second)
				{
					m_stack.push_back(pNew);
					//InterlockedIncrement(&m_nAfterExpandOrShrinkCount);
					++m_nAfterExpandOrShrinkCount;
				}
				else
				{
					log("m_mapOriginalStub.insert 失败，%s  第 %d 行", "CMemBlockPool2::expand_pool", __LINE__);
				}
			}
			catch(...)
			{
				log("异常，%s  第 %d 行", "CMemBlockPool2::expand_pool", __LINE__);

				assert(false);
			}
		}
		else
		{
			char szError[256] = {0};
			sprintf(szError, "%s ，expand_pool 异常 \n", pszTextMark);

			log("%s", szError);

			break;
		}

		iFactCount++;
	}

	log("CMemBlockPool2  扩充，函数名%s 扩充量 %d\n", pszTextMark, iFactCount);

	return iFactCount;
}

/* --------------------------------------------------------------------------
函数说明：收缩池的尺寸，也可以启一个线程来进行收缩会更安全
传入参数：
	nAtLessShrinkCount	至少要收缩的数目
	fShrinkParam 收缩系数
返回值：
	实际收缩的尺寸
--------------------------------------------------------------------------*/
int	 CMemBlockPool2::shrink_pool(int nAtLessShrinkCount, float fShrinkParam)
{
	if(!m_bShrinkPool)	// 不允许收缩
		return 0;

	if( fShrinkParam <= 0 )
		return 0;

	std::lock_guard<std::recursive_mutex> guard(m_lock);

	size_t	nRemainCount = m_stack.size();	// 当前池内的元素数数量

	int nShrinkCount = (int)nRemainCount - m_nInitElementCount.load();	// 差值，即要收缩的数量，
	
	if( nShrinkCount <= 0 )
		return 0;

	if( nShrinkCount > nAtLessShrinkCount )
	{
		nShrinkCount = (int)(nShrinkCount * fShrinkParam);

		if( nShrinkCount < nAtLessShrinkCount )
			nShrinkCount = nAtLessShrinkCount;
	}

	int iFactCount = 0;	// 实际收缩的数量

	for(int i = 0; i < nShrinkCount; i++)
	{
		CMemBlock2* pMsgBlock = m_stack.front();
		m_stack.pop_front();

		{	// 从原始的存根里移除
			MAP_ORIGINAL_STUB::iterator iter =	m_mapOriginalStub.find((CMemBlock2*)pMsgBlock);
			if(iter != m_mapOriginalStub.end())	// 找到啦
			{
				m_mapOriginalStub.erase(iter);
			}
			else	// 没找到
			{
					log("池内的内存块 %lld 未找到 \n", (int64_t)pMsgBlock);
			}
		}


		delete pMsgBlock;
		
		//InterlockedDecrement(&m_nAfterExpandOrShrinkCount);
		++m_nAfterExpandOrShrinkCount;

		iFactCount++;
	}

	log("收缩 CMemBlockPool2 ，收缩数量 %d \n", iFactCount);

	return iFactCount;
}

/* --------------------------------------------------------------------------
函数说明：使用定时器自动收缩池，定时器由别的类提供
传入参数：
	nAtLessShrinkCount	至少要收缩的数目
	fShrinkParam 收缩系数
返回值：
	实际收缩的尺寸
--------------------------------------------------------------------------*/
int CMemBlockPool2::use_timer_shrink_pool(int nAtLessShrinkCount, float fShrinkParam)
{
	return shrink_pool(nAtLessShrinkCount, fShrinkParam);
}

 
int CMemBlockPool2::get_current_element_count()
{
	std::lock_guard<std::recursive_mutex> guard(m_lock);
	
	return static_cast<int>(m_stack.size());
}

// 获得出池的数量
int64_t  CMemBlockPool2::get_retrieve_count()
{
	return (int64_t)m_lRetrieveCount.load();
}

// 获得归池的数量
int64_t  CMemBlockPool2::get_recycle_count()
{
	return m_lRecycleCount;
}

// 重新装填消息头，消息块内的包体内容保持原状不变
int CMemBlockPool2::refill_head(CMemBlock2*& pMemBlock, int64_t lChannelNo, int iMainCode, int iSubCode)
{
	int iRes = 0;

	if(!pMemBlock)
		return 10;	// pMemBlock 是空值

	CORE_MSG_HEAD* pHead = (CORE_MSG_HEAD*)pMemBlock->base();

	if(pMemBlock->length() < sizeof(CORE_MSG_HEAD) )
		return 20;	// pMemBlock 长度太短了

	pHead->_channelNO = lChannelNo;
	pHead->_mainCode = iMainCode;
	pHead->_subCode = iSubCode;

	return 0;
}

// 重新装填消息块，通道号、主码、辅助码保持原来的值不变
int CMemBlockPool2::refill_content(CMemBlock2*& pMemBlock, const char* pBody, int iBodyLen)
{
	int iRes = 0;

	CORE_MSG_HEAD* pMsgHead = NULL;
	iRes = get_core_msg_head(pMemBlock, pMsgHead);

	if(0 != iRes)
	{
		assert(true);
		return 5;
	}

	int64_t	lChannelNo = pMsgHead->_channelNO;		// 通道号，服务端专用
	int			iMainCode = pMsgHead->_mainCode;;
	int			iSubCode = pMsgHead->_subCode;;

	pMemBlock->clear();

	// 获得池里内存块的尺寸
	int iMemSize = get_mem_block_size();

	if((int)sizeof(CORE_MSG_HEAD) + iBodyLen >= iMemSize)
		return 10;	// 包体内容超出消息块的长度啦

	int iSize = sizeof(CORE_MSG_HEAD);

	// 内容赋值
	CORE_MSG_HEAD stCoreMsg;
	stCoreMsg._channelNO = lChannelNo;
	stCoreMsg._mainCode = iMainCode;
	stCoreMsg._subCode = iSubCode;

	stCoreMsg.RaiseTotalSize(iBodyLen);

	pMemBlock->copy((char*)(&stCoreMsg), sizeof(stCoreMsg));	// 包头赋值

	if(pBody && iBodyLen>0)
		pMemBlock->copy(pBody, iBodyLen);	// 包体赋值

	return 0;
}

// 重新装填消息块，通道号保持原来的值不变
int CMemBlockPool2::refill_content(CMemBlock2*& pMemBlock, int iMainCode, int iSubCode, const char* pBody, int iBodyLen)
{
	int iRes = 0;

	int64_t _channelNO = INVALID_CHANNEL_NO;
	iRes = get_core_msg_channel(pMemBlock, _channelNO);
	if(0 != iRes)
	{
		assert(true);
		return 5;
	}

	pMemBlock->clear();

	// 获得池里内存块的尺寸
	int iMemSize = get_mem_block_size();

	if((int)sizeof(CORE_MSG_HEAD) + iBodyLen >= iMemSize)
		return 10;	// 包体内容超出消息块的长度啦

	int iSize = sizeof(CORE_MSG_HEAD);

	// 内容赋值
	CORE_MSG_HEAD stCoreMsg;
	stCoreMsg._channelNO = _channelNO;
	stCoreMsg._mainCode = iMainCode;
	stCoreMsg._subCode = iSubCode;

	stCoreMsg.RaiseTotalSize(iBodyLen);

	pMemBlock->copy((char*)(&stCoreMsg), sizeof(stCoreMsg));	// 包头赋值

	if(pBody && iBodyLen>0)
		pMemBlock->copy(pBody, iBodyLen);	// 包体赋值

	return 0;
}

// 重新装填消息块
int CMemBlockPool2::refill_content(CMemBlock2*& pMemBlock, int64_t lChannelNo, int iMainCode, int iSubCode, const char* pBody, int iBodyLen)
{
	int iRes = 0;

	pMemBlock->clear();

	// 获得池里内存块的尺寸
	int iMemSize = get_mem_block_size();

	if ((int)sizeof(CORE_MSG_HEAD)+iBodyLen >= iMemSize)
		return 10;	// 包体内容超出消息块的长度啦

	int iSize = sizeof(CORE_MSG_HEAD);

	// 内容赋值
	CORE_MSG_HEAD stCoreMsg;
	stCoreMsg._channelNO = lChannelNo;
	stCoreMsg._mainCode = iMainCode;
	stCoreMsg._subCode = iSubCode;

	stCoreMsg.RaiseTotalSize(iBodyLen);

	pMemBlock->copy((char*)(&stCoreMsg), sizeof(stCoreMsg));	// 包头赋值

	if(pBody && iBodyLen>0)
		pMemBlock->copy(pBody, iBodyLen);	// 包体赋值

	return 0;
}

// 向消息块追加内容
int CMemBlockPool2::append_content(CMemBlock2*& pMemBlock, const char* pBody, int iBodyLen)
{
	int iRes = 0;

	if(!pMemBlock)
		return 5;	// 消息块为空

	// 获得池里内存块的尺寸
	int iMemSize = get_mem_block_size();

	if ((int)sizeof(CORE_MSG_HEAD)+iBodyLen >= iMemSize)
		return 10;	// 包体内容超出消息块的长度啦

	int iSize = sizeof(CORE_MSG_HEAD);

	// 追加的内容赋值
	if(pBody && iBodyLen>0)
	{
		CORE_MSG_HEAD* pHead = (CORE_MSG_HEAD*)pMemBlock->base();

		if(pMemBlock->length() < sizeof(CORE_MSG_HEAD) )
			return 20;	// pMemBlock 长度太短了

		pHead->RaiseTotalSize(iBodyLen);

		iRes = pMemBlock->copy(pBody, iBodyLen);	// 包体赋值
		if(0!=iRes)
			return 40;	// 包头或包体赋值失败
	}

	return 0;
}

// 出池一个空的消息块，成功返回0，失败返回错误码
int CMemBlockPool2::retrieve_empty_content(char* pszTextMark, CMemBlock2*& pMemBlock, bool bIsWait)
{
	// 获得池里内存块的尺寸
	int iMemSize = get_mem_block_size();

	bool bFlag = retrieve(&pMemBlock, pszTextMark, bIsWait);	// 出池

	if(!bFlag || !pMemBlock)
	{
		pMemBlock = NULL;
		return 20;	// 消息块出池失败
	}

	return 0;
}

// 出池一个携带错误内容的消息块，主要用于测试
int CMemBlockPool2::retrieve_with_error_content(char* pszTextMark, CMemBlock2*& pMemBlock, int iMainCode, int iSubCode, const char* pBody, int iBodyLen, bool bIsWait)
{
	// 获得池里内存块的尺寸
	int iMemSize = get_mem_block_size();

	if ((int)sizeof(CORE_MSG_HEAD)+iBodyLen >= iMemSize)
		return 10;	// 包体内容超出消息块的长度啦

	bool bFlag = retrieve(&pMemBlock, pszTextMark, bIsWait);	// 出池

	if(!bFlag || !pMemBlock)
	{
		pMemBlock = NULL;
		return 20;	// 消息块出池失败
	}

	int iSize = sizeof(CORE_MSG_HEAD);

	// 内容赋值
	CORE_MSG_HEAD stCoreMsg;
	stCoreMsg.RaiseTotalSize(iBodyLen);

	stCoreMsg._beginFlag = 0x123;	// 固意写错

	stCoreMsg._mainCode = iMainCode;
	stCoreMsg._subCode = iSubCode;

	pMemBlock->copy((char*)(&stCoreMsg), sizeof(stCoreMsg));	// 包头赋值

	if(pBody && iBodyLen>0)
		pMemBlock->copy(pBody, iBodyLen);	// 包体赋值

	if(pMemBlock->length()<=0)
	{
		recycle(pMemBlock, "CMemBlockPool2::retrieve_with_error_content");	// 归池
		return 40;	// 包头或包体赋值失败
	}

	return 0;
}

// 出池一个携带指定内容的消息块
int CMemBlockPool2::retrieve_with_content_no_channel(char* pszTextMark, CMemBlock2*& pMemBlock, int iMainCode, int iSubCode, const char* pBody, int iBodyLen, bool bIsWait)
{
	// 获得池里内存块的尺寸
	int iMemSize = get_mem_block_size();

	if ((int)sizeof(CORE_MSG_HEAD)+iBodyLen >= iMemSize)
		return 10;	// 包体内容超出消息块的长度啦

	bool bFlag = retrieve(&pMemBlock, pszTextMark, bIsWait);	// 出池

	if(!bFlag || !pMemBlock)
	{
		pMemBlock = NULL;
		return 20;	// 消息块出池失败
	}

	int iSize = sizeof(CORE_MSG_HEAD);

	// 内容赋值
	CORE_MSG_HEAD stCoreMsg;
	stCoreMsg.RaiseTotalSize(iBodyLen);

	stCoreMsg._mainCode = iMainCode;
	stCoreMsg._subCode = iSubCode;

	pMemBlock->copy((char*)(&stCoreMsg), sizeof(stCoreMsg));	// 包头赋值

	if(pBody && iBodyLen>0)
		pMemBlock->copy(pBody, iBodyLen);	// 包体赋值

	if(pMemBlock->length()<=0)
	{
		recycle(pMemBlock, "CMemBlockPool2::retrieve_with_content_no_channel");	// 归池
		return 40;	// 包头或包体赋值失败
	}

	return 0;
}

// 出池一个携带指定内容的消息块
int CMemBlockPool2::retrieve_with_content(char* pszTextMark, CMemBlock2*& pMemBlock, int64_t lChannelNo, int iMainCode, int iSubCode, const char* pBody, int iBodyLen, bool bIsWait)
{
	// 获得池里内存块的尺寸
	int iMemSize = get_mem_block_size();

	if ((int)sizeof(CORE_MSG_HEAD)+iBodyLen >= iMemSize)
		return 10;	// 包体内容超出消息块的长度啦

	bool bFlag = retrieve(&pMemBlock, pszTextMark, bIsWait);	// 出池

	if(!bFlag || !pMemBlock)
	{
		pMemBlock = NULL;
		return 20;	// 消息块出池失败
	}

	int iSize = sizeof(CORE_MSG_HEAD);

	// 内容赋值
	CORE_MSG_HEAD stCoreMsg;
	stCoreMsg.RaiseTotalSize(iBodyLen);

	stCoreMsg._channelNO = lChannelNo;
	stCoreMsg._mainCode = iMainCode;
	stCoreMsg._subCode = iSubCode;

	pMemBlock->copy((char*)(&stCoreMsg), sizeof(stCoreMsg));	// 包头赋值

	if(pBody && iBodyLen>0)
		pMemBlock->copy(pBody, iBodyLen);	// 包体赋值

	if(pMemBlock->length()<=0)
	{
		recycle(pMemBlock, "CMemBlockPool2::retrieve_with_content_no_channel");	// 归池
		return 40;	// 包头或包体赋值失败
	}

	return 0;
}

// 获得内核消息的真实数据
int CMemBlockPool2::get_core_msg_data(CMemBlock2* pMemBlock, int* iMainCode, int* iSubCode, char*& pData, int* iDataLen)
{
	pData = NULL;
	*iDataLen = 0;

	if(!pMemBlock)
		return 10;	// pMemBlock 是空值
	
	CORE_MSG_HEAD* pHead = (CORE_MSG_HEAD*)pMemBlock->base();
	CORE_MSG_HEAD* pTmp;

	if(pMemBlock->length() < sizeof(CORE_MSG_HEAD) )
		return 20;	// pMemBlock 长度太短了

	*iMainCode = pHead->_mainCode;
	*iSubCode = pHead->_subCode;

	if(pMemBlock->length() == sizeof(CORE_MSG_HEAD))	// 只有头，没有包体
	{
		return 0;
	}

	pTmp = (CORE_MSG_HEAD*)(pHead + 1);
	pData = (char*)pTmp;

	*iDataLen = pHead->_totalSize - sizeof(CORE_MSG_HEAD);

	return 0;
}

// 获得内核消息的真实数据，服务端专用
int CMemBlockPool2::get_core_msg_data(CMemBlock2* pMemBlock, int64_t* lChannelNo, int* iMainCode, int* iSubCode, char*& pData, int* iDataLen)
{
	pData = NULL;
	*iDataLen = 0;

	if(!pMemBlock)
		return 10;	// pMemBlock 是空值

	CORE_MSG_HEAD* pHead = (CORE_MSG_HEAD*)pMemBlock->base();
	CORE_MSG_HEAD* pTmp;

	if(pMemBlock->length() < sizeof(CORE_MSG_HEAD) )
		return 20;	// pMemBlock 长度太短了

	*lChannelNo = pHead->_channelNO;
	*iMainCode = pHead->_mainCode;
	*iSubCode = pHead->_subCode;

	if(pMemBlock->length() == sizeof(CORE_MSG_HEAD))	// 只有头，没有包体
	{
		return 0;
	}

	pTmp = (CORE_MSG_HEAD*)(pHead + 1);
	pData = (char*)pTmp;

	*iDataLen = pHead->_totalSize - sizeof(CORE_MSG_HEAD);

	return 0;
}

// 获得内核消息的三个主要数据
int CMemBlockPool2::get_core_msg_three_param(CMemBlock2* pMemBlock, int64_t& lChannelNo, int& iMainCode, int& iSubCode)
{
	if(!pMemBlock)
		return 10;	// pMemBlock 是空值

	CORE_MSG_HEAD* pHead = (CORE_MSG_HEAD*)pMemBlock->base();

	if(pMemBlock->length() < sizeof(CORE_MSG_HEAD) )
		return 20;	// pMemBlock 长度太短了

	lChannelNo = pHead->_channelNO;
	iMainCode = pHead->_mainCode;
	iSubCode = pHead->_subCode;

	return 0;
}

// 获得内核消息的头
int CMemBlockPool2::get_core_msg_head(CMemBlock2* pMemBlock, CORE_MSG_HEAD*& pMsgHead)
{
	if(!pMemBlock)
		return 10;	// pMemBlock 是空值

	CORE_MSG_HEAD* pHead = (CORE_MSG_HEAD*)pMemBlock->base();

	if(pMemBlock->length() < sizeof(CORE_MSG_HEAD) )
		return 20;	// pMemBlock 长度太短了

	pMsgHead = pHead;

	return 0;
}

// 获得内核消息的通道号
int CMemBlockPool2::get_core_msg_channel(CMemBlock2* pMemBlock, int64_t& lChannelNo)
{
	if(!pMemBlock)
		return 10;	// pMemBlock 是空值

	CORE_MSG_HEAD* pHead = (CORE_MSG_HEAD*)pMemBlock->base();


	if(pMemBlock->length() < sizeof(CORE_MSG_HEAD) )
		return 20;	// pMemBlock 长度太短了

	lChannelNo = pHead->_channelNO;

	return 0;
}

// 获得内核消息头内的参数值
int CMemBlockPool2::get_core_head_param(CMemBlock2* pMemBlock, TYPE_IN_HEAD typeInHead, int& iVal)
{
	if(!pMemBlock)
		return 10;	// pMemBlock 是空值
	
	CORE_MSG_HEAD* pHead = (CORE_MSG_HEAD*)pMemBlock->base();

	if(pMemBlock->length() < sizeof(CORE_MSG_HEAD) )
		return 20;	// pMemBlock 长度太短了

	switch(typeInHead)
	{
	case TIH_TOTAL_SIZE:
		iVal = pHead->_totalSize;	// 整个消息的长度， sizeof(CORE_MSG) +  iBodyLen 
		break;
	case TIH_PEER_IP:
		iVal = pHead->_peerIP  ;	// 对端主机的IP
		break;
	case TIH_MAIN_CODE:
		iVal = pHead->_mainCode  ;
		break;
	case TIH_SUB_CODE:
		iVal = pHead->_subCode  ;
		break;
	}

	return 0;
}

/* --------------------------------------------------------------------------
函数说明：列印未归池（在池外）的元素
传入参数：
	bDisplay		是否列印
	int iDisplayNum	未归池的最大显示数量
传出参数：
	vecOutPool	未归池（在池外）的元素数组
返回值：
    成功则返回 0，失败返回错误码
--------------------------------------------------------------------------*/
int CMemBlockPool2::display_out_pool(bool bDisplay, std::vector<OUT_POOL_ELEMENT>& vecOutPool, int iDisplayNum)
{
	std::lock_guard<std::recursive_mutex> guard(m_lock);

	using namespace std::chrono;

	vecOutPool.clear();

	bool	bResult = false;
	int		iCount = 0;
	//__int64 timeDisplay = ::GetTickCount64();		// 列印的时间
	auto timeDisplay = std::chrono::high_resolution_clock::now();   // 获得当前时间

	size_t iSize = m_mapOriginalStub.size();
	if (bDisplay && iSize > 0)
	{
			log("列印未归池元素 ,当前时间 %I64d ： \n", timeDisplay);
	}

	try
	{
		MAP_ORIGINAL_STUB::iterator iter = m_mapOriginalStub.begin();
		for( ; iter!=m_mapOriginalStub.end(); iter++)
		{
			CMemBlock2* pMsgBlock = (*iter).first;
			if(pMsgBlock && !pMsgBlock->m_bInPool)	// 池外的元素
			{
				OUT_POOL_ELEMENT tmp;
				tmp.timeOutPool = pMsgBlock->timeOutPool;	// 出池时间
				tmp.timeDisplay = timeDisplay;		// 列印的时间
				pMsgBlock->get_text_mark(tmp.szTextMark, sizeof(tmp.szTextMark)-1);	// 文字标识

				//__int64 lSpace = timeDisplay - tmp.timeOutPool;	// 时差，从出池到显示之间的时间
				duration<double, std::ratio<1, 1000>> time_span_milliseconds = duration_cast<duration<double, std::ratio<1, 1000>>>(timeDisplay - tmp.timeOutPool);   // 间隔，以ms为单位

				// 未归池的时差判定的时长，因为 display_out_pool 时还有一些正常消息在使用中暂未归池，这样的守护不应该被列为未归池（在池外）的元素
				// 只有在时间上大于此值才能被认定为未归池（在池外）的元素
				if (bDisplay && iCount<iDisplayNum && time_span_milliseconds.count()>m_iDieSpace)
				{
						log("  %s, %I64d，时差 %d  \n", 
							tmp.szTextMark, 
							(int64_t)pMsgBlock,							// 未归池（在池外）的元素的指针
							time_span_milliseconds.count()		// 时差
							);
				}

				vecOutPool.push_back(tmp);
				iCount++;
			}
		}

		if (bDisplay)
		{
			log("  未归池元素总数量：%d \n", iCount);
		}
	
	}
	catch (...)
	{
		log("异常 %s \n", "CMemBlockPool2::display_out_pool");
	}

	return bResult;
}

// 显示所有的池信息
void CMemBlockPool2::display_all_pool()
{
		log("池内情况：\n");
		log("  MsgPool，       出池数=%I64d 归池数=%lld 池内当前元素=%d \n",
			get_retrieve_count(),
			get_recycle_count(),
			get_current_element_count()
			);
}